//
// Created by tgl on 9/16/21.
//

#include <memory>
#include <iostream>
#include <cstring>

/// 删除无虚析构函数的基类指针
using InterfacePtr = std::shared_ptr<class Interface>;
class Interface {
    void *small_data;
public:
    Interface(): small_data(operator new(1024)) {}
    ~Interface() {
        std::cout << __FUNCTION__ << std::endl;
        /// 这里没有删除 small_data
    }
    virtual void foo() = 0;
};

class SomeImpl : public Interface {
    void *some_big_data;
public:
    SomeImpl(): some_big_data{operator new(1048576)} {
        std::cout << __FUNCTION__ << std::endl;
    }
    ~SomeImpl() {
        operator delete(some_big_data);
        std::cout << __FUNCTION__ << std::endl;
    }

    void foo() override {
        std::cout << __FUNCTION__ << std::endl;
    }
};
void UseInterface(InterfacePtr ptr)
{
    if (ptr)
        ptr->foo();
}
/// 删除无虚析构函数的基类指针

/// shared_ptr 相互依赖的问题
using NodePtr = std::shared_ptr<struct Node>;
using WeakNode = std::weak_ptr<struct Node>; /// 使用 std::weak_ptr 来解决问题
struct Node {
    NodePtr parent;
    NodePtr child;

    Node() {
        std::cout << __FUNCTION__ << this << std::endl;
    }
    ~Node() {
        std::cout << __FUNCTION__ << this << std::endl;
    }
};

void make_cycle_node() {
    /// 只是为了说明循环引用会引发问题
    NodePtr parent = std::make_shared<Node>();    /// parent ref = 1
    NodePtr child = std::make_shared<Node>();     /// child ref = 1
    parent->child = child;                        /// parent ref = 1, child ref = 2
    child->parent = parent;                       /// parent ref = 2, child ref = 2
    /// child EOL, parent ref = 2, child ref = 1
    /// parent EOL, parent ref = 1, child ref = 1
}

int main() {
    // 1
    for (int i=0; i<10; ++i)
        UseInterface(InterfacePtr{(Interface*)new SomeImpl}); /// 这里有内存泄露
    /// 这里只是为了 delete new 出来的指针才使用 shared_ptr
    /// 加(Interface*)强转是为了防止编译器使用 template<class Y> shared_ptr<T>::shared_ptr(Y *p)这个构造函数
    // 2
    make_cycle_node();

    /// 一些函数会返回动态内存，这些内存需要使用者释放
    char long_string[4096];
    memset(long_string, 'A', sizeof(long_string));
    long_string[sizeof(long_string)-1] = 0;

    for (int i=0; i<100; ++i) {
        char *new_string = strdup(long_string);
        // use new_string here
        free(new_string);
    }
}


